package cz.cuni.amis.episodic.bayes.utils;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.YIntervalSeries;
import org.jfree.data.xy.YIntervalSeriesCollection;

import cz.cuni.amis.episodic.bayes.experiment.Experiment;
import cz.cuni.amis.episodic.bayes.utils.chart.GraphPaintingDevice;
import cz.cuni.amis.episodic.bayes.utils.chart.SeriesApperanceStrategy;

public class MultiexperimentSummary {

	public static List<Entry<Integer, Map<String, Map<String, DescriptiveStatistics[][]>>>> loadMultiExperimentResultData(
			String expsRootFolder) throws Exception {
		File rootDir = new File(expsRootFolder);

		// list all experiments
		File[] experimentDirs = rootDir.listFiles();

		// load data from all experiments
		Map<Integer, Map<String, Map<String, DescriptiveStatistics[][]>>> expsResults = new HashMap<>();
		for (File expDir : experimentDirs) {
			if (expDir.isDirectory()) {
				try {
					Map<String, Map<String, DescriptiveStatistics[][]>> data = Experiment
							.loadResults(expDir);
					int x = Integer.parseInt(expDir.getName().split("-")[1]);

					expsResults.put(x, data);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		// sort
		List<Entry<Integer, Map<String, Map<String, DescriptiveStatistics[][]>>>> list = new ArrayList<>(
				expsResults.entrySet());
		Collections
				.sort(list,
						new Comparator<Entry<Integer, Map<String, Map<String, DescriptiveStatistics[][]>>>>() {
							@Override
							public int compare(
									Entry<Integer, Map<String, Map<String, DescriptiveStatistics[][]>>> o1,
									Entry<Integer, Map<String, Map<String, DescriptiveStatistics[][]>>> o2) {
								return o1.getKey() - o2.getKey();
							}
						});
		return list;
	}

	/**
	 * Create one series.
	 * 
	 * @param list
	 * @param architecture
	 * @param strategy
	 * @param level
	 * @param mem
	 * @return
	 */
	public static YIntervalSeries createSeries(
			List<Entry<Integer, Map<String, Map<String, DescriptiveStatistics[][]>>>> list,
			String architecture, String strategy, int level, int mem,
			SeriesApperanceStrategy apperance) {

		String label = apperance.labelFor(architecture, strategy, level, mem);

		YIntervalSeries series = new YIntervalSeries(label);
		for (Entry<Integer, Map<String, Map<String, DescriptiveStatistics[][]>>> entry : list) {

			DescriptiveStatistics stat = entry.getValue().get(architecture)
					.get(strategy)[level][mem];
			// double[] vals = stat2.getValues();
			// for (int i = 0; i < vals.length; i++) {
			// vals[i] *= 100;
			// }
			// DescriptiveStatistics stat = new DescriptiveStatistics(vals);

			// use percentile

			// double interval = 25;
			// series.add(entry.getKey(), stat.getMean(),
			// stat.getPercentile(50 - interval),
			// stat.getPercentile(50 + interval));

			// use variance
			double var = stat.getStandardDeviation()
			 * stat.getStandardDeviation();

			series.add(entry.getKey(), stat.getMean(), stat.getMean() - var,
					stat.getMean() + var);
			
			//series.add(entry.getKey(), stat.getMean(),
			//		stat.getMean() - stat.getStandardDeviation(),
			//		stat.getMean() + stat.getStandardDeviation());
		}

		return series;
	}

	public static YIntervalSeriesCollection createGraphDataset(
			List<Entry<Integer, Map<String, Map<String, DescriptiveStatistics[][]>>>> list,
			String[] architectures, String[] strategies, int[] levels,
			int[] mems) {
		return createGraphDataset(list, architectures, strategies, levels,
				mems, new SeriesApperanceStrategy());
	}

	public static YIntervalSeriesCollection createGraphDataset(
			List<Entry<Integer, Map<String, Map<String, DescriptiveStatistics[][]>>>> list,
			String[] architectures, String[] strategies, int[] levels,
			int[] mems, SeriesApperanceStrategy apperance) {

		YIntervalSeriesCollection dataset = new YIntervalSeriesCollection();

		for (int i = 0; i < architectures.length; i++) {

			for (String strategy : strategies) {
				for (int level : levels) {
					for (int memNum : mems) {
						dataset.addSeries(createSeries(list, architectures[i],
								strategy, level, memNum, apperance));
					}
				}
			}
		}
		return dataset;
	}

	public static void outputTrainingDataInfluenceGraph(String graphName,
			XYDataset xydataset, GraphPaintingDevice device) throws Exception {
		JFreeChart jfreechart = DeviationGraph.createChart(xydataset,
				"Training sequences", "Recall accuracy");
		device.outputGraph(jfreechart, graphName);
	}

	public static void showTrainingDataInfluenceGraph(XYDataset xydataset) {
		DeviationGraph.showGraph(xydataset, "Training sequences",
				"Recall accuracy");
	}

}
